package com.chebaohui.iqs.sdk;

import java.net.InetAddress;

/**
 * 数据库主键id生成器
 * 
 * @author regas_xie
 *
 */
public class IdWorker {
	private final long workerId;
	private long sequence = 0L;
	// private static final long twepoch = 1361753741828L;
	// private static final long workerIdBits = 10L;
	// private static final long maxWorkerId = 1023L;
	// private static final long sequenceBits = 12L;
	// private static final long workerIdShift = 12L;
	// private static final long timestampLeftShift = 22L;
	// private static final long sequenceMask = 4095L;
	private long lastTimestamp = -1L;

	private static IdWorker worker = new IdWorker();

	public IdWorker() {
		this.workerId = (getAddress() % 1024L);
	}

	public static Long getId() {
		return Long.valueOf(worker.nextId());
	}

	public synchronized long nextId() {
		long timestamp = timeGen();
		if (this.lastTimestamp == timestamp) {
			this.sequence = (this.sequence + 1L & 0xFFF);
			if (this.sequence == 0L)
				timestamp = tilNextMillis(this.lastTimestamp);
		} else {
			this.sequence = 0L;
		}
		if (timestamp < this.lastTimestamp) {
			try {
				throw new Exception(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
						new Object[] { Long.valueOf(this.lastTimestamp - timestamp) }));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		this.lastTimestamp = timestamp;
		long nextId = timestamp - 1361753741828L << 22 | this.workerId << 12 | this.sequence;

		return nextId;
	}

	private long tilNextMillis(long lastTimestamp1) {
		long timestamp = timeGen();
		while (timestamp <= lastTimestamp1) {
			timestamp = timeGen();
		}
		return timestamp;
	}

	private static long getAddress() {
		try {
			String currentIpAddress = InetAddress.getLocalHost().getHostAddress();
			String[] str = currentIpAddress.split("\\.");
			StringBuilder hardware = new StringBuilder();
			for (int i = 0; i < str.length; i++) {
				hardware.append(str[i]);
			}
			return Long.parseLong(hardware.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}

		return 2L;
	}

	private long timeGen() {
		return System.currentTimeMillis();
	}
}